#include "wildcards.hh"
#include "hook.h"
#include "CInGame.h"

#define ISERVER_LOG() if(set_iDebug >= 2) AddLog(__FUNCSIG__);
#define ISERVER_LOGARG_WS(a) if(set_iDebug >= 2) AddLog("     " #a ": %s", wstos((const wchar_t*)a).c_str());
#define ISERVER_LOGARG_S(a) if(set_iDebug >= 2) AddLog("     " #a ": %s", (const char*)a);
#define ISERVER_LOGARG_UI(a) if(set_iDebug >= 2) AddLog("     " #a ": %u", (uint)a);
#define ISERVER_LOGARG_I(a) if(set_iDebug >= 2) AddLog("     " #a ": %d", (int)a);
#define ISERVER_LOGARG_F(a) if(set_iDebug >= 2) AddLog("     " #a ": %f", (float)a);

namespace HkIServerImpl
{

/**************************************************************************************************************
this is our "main" loop
**************************************************************************************************************/

// add timers here
typedef void (*_TimerFunc)();

struct TIMER
{
	_TimerFunc	proc;
	mstime		tmIntervallMS;
	mstime		tmLastCall;
};

TIMER Timers[] = 
{
	{ProcessPendingCommands,		50,					0},
	{HkTimerUpdatePingData,			1000,				0},
	{HkTimerUpdateLossData,			LOSS_INTERVALL,		0},
	{HkTimerCheckKick,				1000,				0},
	{HkTimerNPCAndF1Check,			50,					0},
	{HkTimerCheckIfBaseDestroyed,	1000,				0},
	{HkTimerCheckResolveResults,	0,					0},
};

int __stdcall Update(void)
{
	static bool bFirstTime = true;
	if(bFirstTime)
	{
		FLHookInit();
		bFirstTime = false;
	}

	// call timers
	for(uint i = 0; (i < sizeof(Timers)/sizeof(TIMER)); i++)
	{
		if((timeInMS() - Timers[i].tmLastCall) >= Timers[i].tmIntervallMS)
		{
			Timers[i].tmLastCall = timeInMS();
			Timers[i].proc();
		}
	}

	char *pData;
	memcpy(&pData, g_FLServerDataPtr + 0x40, 4);
	memcpy(&g_iServerLoad, pData + 0x204, 4);

	int iRet = Server.Update();
	return iRet;
}

/**************************************************************************************************************
Chat-Messages are hooked here
<Parameters>
cId:       Sender's ClientID
lP1:       size of rdlReader (used when extracting text from that buffer)
rdlReader: RenderDisplayList which contains the chat-text
cIdTo:     recipient's clientid(0x10000 = universe chat else when (cIdTo & 0x10000) = true -> system chat)
iP2:       ???
**************************************************************************************************************/

CInGame admin;
bool g_bInSubmitChat = false;
uint g_iTextLen = 0;

void __stdcall SubmitChat(struct CHAT_ID cId, unsigned long lP1, void const *rdlReader, struct CHAT_ID cIdTo, int iP2)
{
	wchar_t wszBuf[1024] = L"";

	try {
		if(cIdTo.iID == 0x10004)
		{
			g_bInSubmitChat = true;
			Server.SubmitChat(cId, lP1, rdlReader, cIdTo, iP2);
			g_bInSubmitChat = false;
			return;
		}

		// extract text from rdlReader
		BinaryRDLReader rdl;
		uint iRet1;
		rdl.extract_text_from_buffer(wszBuf, sizeof(wszBuf), iRet1, (const char*)rdlReader, lP1);
		wstring wscBuf = wszBuf;
		g_iTextLen = (uint)wscBuf.length();
		if(!wscBuf.find(L"/u ") || !wscBuf.find(L"/s ") || !wscBuf.find(L"/g "))
			g_iTextLen -= 3;
		uint iClientID = cId.iID;

		// check for user cmds
		if(UserCmd_Process(iClientID, wscBuf))
			return;

		if(wszBuf[0] == '.')
		{ // flhook admin command
			CAccount *acc = Players.FindAccountFromClientID(iClientID);
			wstring wscAccDirname;

			HkGetAccountDirName(acc, wscAccDirname);
			string scAdminFile = scAcctPath + wstos(wscAccDirname) + "\\flhookadmin.ini";
			WIN32_FIND_DATA fd;
			HANDLE hFind = FindFirstFile(scAdminFile.c_str(), &fd);
			if(hFind != INVALID_HANDLE_VALUE)
			{ // is admin
				FindClose(hFind);
				admin.ReadRights(scAdminFile);
				admin.iClientID = iClientID;
				admin.wscAdminName = Players.GetActiveCharacterName(iClientID);
				admin.ExecuteCommandString(wszBuf + 1);
				return;
			}
		}

		// process chat event
		wstring wscEvent;
		wscEvent.reserve(256);
		wscEvent = L"chat";
		wscEvent += L" from=";
		if(!cId.iID)
			wscEvent += L"console";
		else
			wscEvent += Players.GetActiveCharacterName(cId.iID);

		wscEvent += L" id=";
		wscEvent += stows(itos(cId.iID));

		wscEvent += L" type=";
		if(cIdTo.iID == 0x00010000)
			wscEvent += L"universe";
		else if(cIdTo.iID & 0x00010000)
			wscEvent += L"system";
		else {
			wscEvent += L"player";
			wscEvent += L" to=";

			if(!cIdTo.iID)
				wscEvent += L"console";
			else
				wscEvent += Players.GetActiveCharacterName(cIdTo.iID);

			wscEvent += L" idto=";
			wscEvent += stows(itos(cIdTo.iID));
		}

		wscEvent += L" text=";
		wscEvent += wscBuf;
		ProcessEvent(wscEvent);

		// check if chat should be suppressed
		foreach(set_lstChatSuppress, wstring, i)
		{
			if((ToLower(wscBuf)).find(ToLower(*i)) == 0)
				return;
		}
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	// send
	g_bInSubmitChat = true;
	try { 
		Server.SubmitChat(cId, lP1, rdlReader, cIdTo, iP2);
	} catch(...) { AddLog("Exception in Server.SubmitChat"); }
	g_bInSubmitChat = false;
}

/**************************************************************************************************************
Called when player ship was created in space (after undock or login)
**************************************************************************************************************/

void __stdcall PlayerLaunch(unsigned int iShip, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iShip);
	ISERVER_LOGARG_UI(iClientID);

	try {
		ClientInfo[iClientID].iShip = iShip;
		ClientInfo[iClientID].iKillsInARow = 0;
		ClientInfo[iClientID].bCruiseActivated = false;
		ClientInfo[iClientID].bThrusterActivated = false;
		ClientInfo[iClientID].bEngineKilled = false;
		ClientInfo[iClientID].bTradelane = false;

		// adjust cash, this is necessary when cash was added while use was in charmenu/had other char selected
		wstring wscCharname = Players.GetActiveCharacterName(iClientID);
		foreach(ClientInfo[iClientID].lstMoneyFix, MONEY_FIX, i)
		{
			if(!(*i).wscCharname.compare(wscCharname))
			{
				HkAddCash(wscCharname, (*i).iAmount);
				ClientInfo[iClientID].lstMoneyFix.remove(*i);
				break;
			}
		}
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.PlayerLaunch(iShip, iClientID);

	try {
		if(!ClientInfo[iClientID].iLastExitedBaseID)
		{
			ClientInfo[iClientID].iLastExitedBaseID = 1;

			// event
			ProcessEvent(L"spawn char=%s id=%d system=%s", 
					Players.GetActiveCharacterName(iClientID), 
					iClientID,
					HkGetPlayerSystem(iClientID).c_str());
		}
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called when player fires a weapon
**************************************************************************************************************/

void __stdcall FireWeapon(unsigned int iClientID, struct XFireWeaponInfo const &wpn)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.FireWeapon(iClientID, wpn);
}

/**************************************************************************************************************
Called when one player hits a target with a gun
<Parameters>
ci:  only figured out where dwTargetShip is ...
**************************************************************************************************************/

void __stdcall SPMunitionCollision(struct SSPMunitionCollisionInfo const & ci, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	uint iClientIDTarget;

	try {
		iClientIDTarget = HkGetClientIDByShip(ci.dwTargetShip);
		if(iClientIDTarget && !AllowPlayerDamage(iClientID, iClientIDTarget))
			return;

	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	iDmgTo = iClientIDTarget;
	Server.SPMunitionCollision(ci, iClientID);
}

/**************************************************************************************************************
Called when player moves his ship
**************************************************************************************************************/

void __stdcall SPObjUpdate(struct SSPObjUpdateInfo const &ui, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.SPObjUpdate(ui, iClientID);

	try {
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}
/**************************************************************************************************************
Called when one player collides with a space object
**************************************************************************************************************/

void __stdcall SPObjCollision(struct SSPObjCollisionInfo const &ci, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		uint iClientIDTarget = HkGetClientIDByShip(ci.dwTargetShip);
		if(iClientIDTarget && !AllowPlayerDamage(iClientID, iClientIDTarget))
			return;

	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.SPObjCollision(ci, iClientID);
}

/**************************************************************************************************************
Called when player has undocked and is now ready to fly
**************************************************************************************************************/

void __stdcall LaunchComplete(unsigned int iBaseID, unsigned int iShip)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iBaseID);
	ISERVER_LOGARG_UI(iShip);

	try {
		uint iClientID = HkGetClientIDByShip(iShip);
		if(iClientID)
			ClientInfo[iClientID].tmSpawnTime = timeInMS(); // save for anti-dockkill

		// event
		ProcessEvent(L"launch char=%s id=%d base=%s system=%s", 
				Players.GetActiveCharacterName(iClientID), 
				iClientID,
				HkGetBaseNickByID(ClientInfo[iClientID].iLastExitedBaseID).c_str(),
				HkGetPlayerSystem(iClientID).c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.LaunchComplete(iBaseID, iShip);
}

/**************************************************************************************************************
Called when player selects a character
**************************************************************************************************************/

void __stdcall CharacterSelect(struct CHARACTER_ID const & cId, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_S(&cId);
	ISERVER_LOGARG_UI(iClientID);

	wstring wscCharBefore;
	try {
		const wchar_t *wszCharname = Players.GetActiveCharacterName(iClientID);
		wscCharBefore = wszCharname ? Players.GetActiveCharacterName(iClientID) : L"";
		ClientInfo[iClientID].iLastExitedBaseID = 0;
		Server.CharacterSelect(cId, iClientID);
	} catch(...) {
		HkAddKickLog(iClientID, L"Corrupt charfile?");
		HkKick(ARG_CLIENTID(iClientID));
		return;
	}

	try {
		wstring wscCharname = Players.GetActiveCharacterName(iClientID);

		if(wscCharBefore.compare(wscCharname) != 0)
			LoadUserCharSettings(iClientID);

		// anti-cheat check
		list <CARGO_INFO> lstCargo;
		int iHold;
		HkEnumCargo(ARG_CLIENTID(iClientID), lstCargo, iHold);
		foreach(lstCargo, CARGO_INFO, it)
		{
			if((*it).iCount < 0)
			{
				HkAddCheaterLog(wscCharname, L"Negative good-count, likely to have cheated in the past");

				wchar_t wszBuf[256];
				swprintf(wszBuf, L"Possible cheating detected (%s)", wscCharname.c_str());
				HkMsgU(wszBuf);
				HkBan(ARG_CLIENTID(iClientID), true);
				HkKick(ARG_CLIENTID(iClientID));
			}
		}

		// event
		CAccount *acc = Players.FindAccountFromClientID(iClientID);
		wstring wscDir;
		HkGetAccountDirName(acc, wscDir);
		HKPLAYERINFO pi;
		HkGetPlayerInfo(ARG_CLIENTID(iClientID), pi, false);
		ProcessEvent(L"login char=%s accountdirname=%s id=%d ip=%s", 
				wscCharname.c_str(),
				wscDir.c_str(),
				iClientID,
				pi.wscIP.c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called when player enters base
**************************************************************************************************************/

void __stdcall BaseEnter(unsigned int iBaseID, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iBaseID);
	ISERVER_LOGARG_UI(iClientID);

	Server.BaseEnter(iBaseID, iClientID);

/*	Archetype::Equipment *eq;
	eq = Archetype::GetEquipment(2487743822); // Stalker MissileGun
	FILE *f = fopen("test.txt", "wt");
	eq = Archetype::GetEquipment(2797456458); // Heavy Starbeam Gun
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(3219265993); // Justice Mk I Gun
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(3024599373); // Javelin Missile
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2487743822); // Stalker MissileGun
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2960932227); // Starkiller Torpedo
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2424062339); // Sunslayer Torpedo
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(3112104454); // Wasp
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2575207942); // Hornet
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2300089610); // Drone Mine Dropper
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2836977929); // Seeker Mine Dropper
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2199282693); // Imp CM
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2736156677); // Adv CM
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2911012559); // nanobots
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2866034054); // h-fuel
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	eq = Archetype::GetEquipment(2688493056); // novabomb
	for(uint i = 0; (i < sizeof(Archetype::Equipment)/4); i++) fprintf(f, "%.8X ", *((uint*)((char*)eq + 4*i))); fprintf(f, "\n");
	fclose(f); */
	


	try {
		// adjust cash, this is necessary when cash was added while use was in charmenu/had other char selected
		wstring wscCharname = Players.GetActiveCharacterName(iClientID);
		foreach(ClientInfo[iClientID].lstMoneyFix, MONEY_FIX, i)
		{
			if(!(*i).wscCharname.compare(wscCharname))
			{
				HkAddCash(wscCharname, (*i).iAmount);
				ClientInfo[iClientID].lstMoneyFix.remove(*i);
				break;
			}
		}

		// anti base-idle
		ClientInfo[iClientID].iBaseEnterTime = (uint)time(0);

		// autobuy
		if(set_bAutoBuy)
			HkPlayerAutoBuy(iClientID, iBaseID);

		// event
		ProcessEvent(L"baseenter char=%s id=%d base=%s system=%s", 
				Players.GetActiveCharacterName(iClientID), 
				iClientID,
				HkGetBaseNickByID(iBaseID).c_str(),
				HkGetPlayerSystem(iClientID).c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called when player exits base
**************************************************************************************************************/

void __stdcall BaseExit(unsigned int iBaseID, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iBaseID);
	ISERVER_LOGARG_UI(iClientID);

	try {
		ClientInfo[iClientID].iBaseEnterTime = 0;
		ClientInfo[iClientID].iLastExitedBaseID = iBaseID;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.BaseExit(iBaseID, iClientID);

	try {
		const wchar_t *wszCharname = Players.GetActiveCharacterName(iClientID);

		// event
		ProcessEvent(L"baseexit char=%s id=%d base=%s system=%s", 
				Players.GetActiveCharacterName(iClientID), 
				iClientID,
				HkGetBaseNickByID(iBaseID).c_str(),
				HkGetPlayerSystem(iClientID).c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}
/**************************************************************************************************************
Called when player connects
**************************************************************************************************************/

void __stdcall OnConnect(unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		if(ClientInfo[iClientID].tmF1TimeDisconnect > timeInMS())
			return;

		ClientInfo[iClientID].iConnects++;
		ClearClientInfo(iClientID);
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.OnConnect(iClientID);

	try {
		// event
		wstring wscIP;
		HkGetPlayerIP(iClientID, wscIP);
		ProcessEvent(L"connect id=%d ip=%s", 
				iClientID,
				wscIP.c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called when player disconnects
**************************************************************************************************************/

void __stdcall DisConnect(unsigned int iClientID, enum EFLConnection p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_UI(p2);

	try {
		ClientInfo[iClientID].lstMoneyFix.clear();

		if(!ClientInfo[iClientID].bDisconnected)
		{
			ClientInfo[iClientID].bDisconnected = true;

			// event
			const wchar_t *wszCharname = Players.GetActiveCharacterName(iClientID);
			ProcessEvent(L"disconnect char=%s id=%d", 
					(wszCharname ? wszCharname : L""), 
					iClientID);
		}
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.DisConnect(iClientID, p2);
}

/**************************************************************************************************************
Called when trade is being terminated
**************************************************************************************************************/

void __stdcall TerminateTrade(unsigned int iClientID, int iAccepted)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_I(iAccepted);

	Server.TerminateTrade(iClientID, iAccepted);

	try {
		if(iAccepted)
		{ // save both chars to prevent cheating in case of server crash
			HkSaveChar(ARG_CLIENTID(iClientID));
			if(ClientInfo[iClientID].iTradePartner)
				HkSaveChar(ARG_CLIENTID(ClientInfo[iClientID].iTradePartner));
		}
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called when new trade request
**************************************************************************************************************/

void __stdcall InitiateTrade(unsigned int iClientID1, unsigned int iClientID2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID1);
	ISERVER_LOGARG_UI(iClientID2);

	try {
		// save traders client-ids
		ClientInfo[iClientID1].iTradePartner = iClientID2;
		ClientInfo[iClientID2].iTradePartner = iClientID1;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.InitiateTrade(iClientID1, iClientID2);
}

/**************************************************************************************************************
Called when equipment is being activated/disabled
**************************************************************************************************************/

void __stdcall ActivateEquip(unsigned int iClientID, struct XActivateEquip const &aq)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		if((aq.sID == 0x23) && !aq.bActivate)
			ClientInfo[iClientID].bCruiseActivated = false; // enginekill enabled

		ClientInfo[iClientID].bEngineKilled = !aq.bActivate;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.ActivateEquip(iClientID, aq);
}

/**************************************************************************************************************
Called when cruise engine is being activated/disabled
**************************************************************************************************************/

void __stdcall ActivateCruise(unsigned int iClientID, struct XActivateCruise const &ac)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		ClientInfo[iClientID].bCruiseActivated = ac.bActivate;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.ActivateCruise(iClientID, ac);
}

/**************************************************************************************************************
Called when thruster is being activated/disabled
**************************************************************************************************************/

void __stdcall ActivateThrusters(unsigned int iClientID, struct XActivateThrusters const &at)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		ClientInfo[iClientID].bThrusterActivated = at.bActivate;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
	Server.ActivateThrusters(iClientID, at);
}

/**************************************************************************************************************
Called when player sells good on a base
**************************************************************************************************************/

void __stdcall GFGoodSell(struct SGFGoodSellInfo const &gsi, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		// anti-cheat check
		list <CARGO_INFO> lstCargo;
		int iHold;
		HkEnumCargo(ARG_CLIENTID(iClientID), lstCargo, iHold);
		foreach(lstCargo, CARGO_INFO, it)
		{
			if(((*it).iArchID == gsi.iArchID) && (abs(gsi.iCount) > (*it).iCount))
			{
				const wchar_t *wszCharname = Players.GetActiveCharacterName(iClientID);
				HkAddCheaterLog(wszCharname, L"Sold more good than possible");

				wchar_t wszBuf[256];
				swprintf(wszBuf, L"Possible cheating detected (%s)", wszCharname);
				HkMsgU(wszBuf);
				HkBan(ARG_CLIENTID(iClientID), true);
				HkKick(ARG_CLIENTID(iClientID));
			}
		}
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.GFGoodSell(gsi, iClientID);
}

/**************************************************************************************************************
Called when player connects or pushes f1
**************************************************************************************************************/

void __stdcall CharacterInfoReq(unsigned int iClientID, bool p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_UI(p2);

	try {
		if(!ClientInfo[iClientID].bCharSelected)
			ClientInfo[iClientID].bCharSelected = true;
		else { // pushed f1
			uint iShip = 0;
			pub::Player::GetShip(iClientID, iShip);
			if(iShip)
			{ // in space
				ClientInfo[iClientID].tmF1Time = timeInMS() + set_iAntiF1;
				return;
			}
		}

//		HkAddConnectLog(iClientID);
		Server.CharacterInfoReq(iClientID, p2);
	} catch(...) { // something is wrong with charfile
		HkAddKickLog(iClientID, L"Corrupt charfile?");
		HkKick(ARG_CLIENTID(iClientID));
		return;
	}
}

/**************************************************************************************************************
Called when player jumps in system
**************************************************************************************************************/

void __stdcall JumpInComplete(unsigned int iSystemID, unsigned int iShip)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iSystemID);
	ISERVER_LOGARG_UI(iShip);

	Server.JumpInComplete(iSystemID, iShip);

	try {
		uint iClientID = HkGetClientIDByShip(iShip);
		if(!iClientID)
			return;

		// event
		ProcessEvent(L"jumpin char=%s id=%d system=%s", 
				Players.GetActiveCharacterName(iClientID), 
				iClientID,
				HkGetSystemNickByID(iSystemID).c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called when player jumps out of system
**************************************************************************************************************/

void __stdcall SystemSwitchOutComplete(unsigned int iShip, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iShip);
	ISERVER_LOGARG_UI(iClientID);

	try {
		// event
		ProcessEvent(L"switchout char=%s id=%d system=%s", 
				Players.GetActiveCharacterName(iClientID), 
				iClientID,
				HkGetPlayerSystem(iClientID).c_str());
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.SystemSwitchOutComplete(iShip, iClientID);
}

/**************************************************************************************************************
Called when player logs in
**************************************************************************************************************/

void __stdcall Login(struct SLoginInfo const &li, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_WS(&li);
	ISERVER_LOGARG_UI(iClientID);

	Server.Login(li, iClientID);

	try {
		if(iClientID > Players.GetMaxPlayerCount())
			return; // lalala DisconnectDelay bug

		if(!HkIsValidClientID(iClientID))
			return; // player was kicked

		// check for ip ban
		wstring wscIP;
		HkGetPlayerIP(iClientID, wscIP);

		foreach(set_lstBans, wstring, itb)
		{
			if(Wildcard::wildcardfit(wstos(*itb).c_str(), wstos(wscIP).c_str()))
			{
				HkAddKickLog(iClientID, L"IP/Hostname ban(%s matches %s)", wscIP.c_str(), (*itb).c_str());
				if(set_bBanAccountOnMatch)
					HkBan(ARG_CLIENTID(iClientID), true);
				HkKick(ARG_CLIENTID(iClientID));
			}
		}

		// resolve
		RESOLVE_IP rip;
		rip.wscIP = wscIP;
		rip.wscHostname = L"";
		rip.iConnects = ClientInfo[iClientID].iConnects; // security check so that wrong person doesnt get banned
		rip.iClientID = iClientID;
		EnterCriticalSection(&csIPResolve);
		g_lstResolveIPs.push_back(rip);
		LeaveCriticalSection(&csIPResolve);

		// count players
		struct PlayerData *pPD = 0;
		uint iPlayers = 0;
		while(pPD = Players.traverse_active(pPD))
			iPlayers++;

		if(iPlayers > (Players.GetMaxPlayerCount() -  set_iReservedSlots))
		{ // check if player has a reserved slot
			CAccount *acc = Players.FindAccountFromClientID(iClientID);
			wstring wscDir; 
			HkGetAccountDirName(acc, wscDir); 
			string scUserFile = scAcctPath + wstos(wscDir) + "\\flhookuser.ini";

			bool bReserved = IniGetB(scUserFile, "Settings", "ReservedSlot", false);
			if(!bReserved)
			{
				HkKick(ARG_CLIENTID(iClientID));
				return;
			}
		}

		LoadUserSettings(iClientID);
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
}

/**************************************************************************************************************
Called on item spawn
**************************************************************************************************************/

void __stdcall MineAsteroid(unsigned int p1, class Vector const &vPos, unsigned int iLookID, unsigned int iGoodID, unsigned int iCount, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_UI(vPos);
	ISERVER_LOGARG_UI(iLookID);
	ISERVER_LOGARG_UI(iGoodID);
	ISERVER_LOGARG_UI(iCount);
	ISERVER_LOGARG_UI(iClientID);

	try {
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.MineAsteroid(p1, vPos, iLookID, iGoodID, iCount, iClientID);
}

/**************************************************************************************************************
**************************************************************************************************************/

void __stdcall GoTradelane(unsigned int iClientID, struct XGoTradelane const &gtl)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	try {
		ClientInfo[iClientID].bTradelane = true;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }
	Server.GoTradelane(iClientID, gtl);
}

/**************************************************************************************************************
**************************************************************************************************************/

void __stdcall StopTradelane(unsigned int iClientID, unsigned int p2, unsigned int p3, unsigned int p4)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_UI(p4);

	try {
		ClientInfo[iClientID].bTradelane = false;
	} catch(...) { AddLog("Exception in %s", __FUNCTION__); }

	Server.StopTradelane(iClientID, p2, p3, p4);
}

////////////////////////////////////////////////////////

void __stdcall AbortMission(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.AbortMission(p1, p2);
}

void __stdcall AcceptTrade(unsigned int iClientID, bool p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_UI(p2);

	Server.AcceptTrade(iClientID, p2);
}

void __stdcall AddTradeEquip(unsigned int iClientID, struct EquipDesc const &ed)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.AddTradeEquip(iClientID, ed);
}

void __stdcall BaseInfoRequest(unsigned int p1, unsigned int p2, bool p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);

	Server.BaseInfoRequest(p1, p2, p3);
}

void __stdcall CharacterSkipAutosave(unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.CharacterSkipAutosave(iClientID);
}

void __stdcall CommComplete(unsigned int p1, unsigned int p2, unsigned int p3,enum CommResult cr)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_UI(cr);

	Server.CommComplete(p1, p2, p3, cr);
}

void __stdcall Connect(char const *p1, unsigned short *p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_WS(p2);

	Server.Connect(p1, p2); // doesn't do anything
}

void __stdcall CreateNewCharacter(struct SCreateCharacterInfo const & scci, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.CreateNewCharacter(scci, iClientID);
}

void __stdcall DelTradeEquip(unsigned int iClientID, struct EquipDesc const &ed)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.DelTradeEquip(iClientID, ed);
}

void __stdcall DestroyCharacter(struct CHARACTER_ID const &cId, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_S(&cId);

	Server.DestroyCharacter(cId, iClientID);
}

void __stdcall Dock(unsigned int const &p1, unsigned int const &p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.Dock(p1, p2);
}

void __stdcall DumpPacketStats(char const *p1)
{
	ISERVER_LOG();

	Server.DumpPacketStats(p1);
}

void __stdcall ElapseTime(float p1)
{
	ISERVER_LOG();
	ISERVER_LOGARG_F(p1);

	Server.ElapseTime(p1);
}

void __stdcall GFGoodBuy(struct SGFGoodBuyInfo const &gbi, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.GFGoodBuy(gbi, iClientID);
}

void __stdcall GFGoodVaporized(struct SGFGoodVaporizedInfo const &gvi, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.GFGoodVaporized(gvi, iClientID);
}

void __stdcall GFObjSelect(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.GFObjSelect(p1, p2);
}

unsigned int __stdcall GetServerID(void)
{
	ISERVER_LOG();

	return Server.GetServerID();
}

char const * __stdcall GetServerSig(void)
{
	ISERVER_LOG();

	return Server.GetServerSig();
}

void __stdcall GetServerStats(struct ServerStats &ss)
{
	ISERVER_LOG();

	Server.GetServerStats(ss);
}

void __stdcall Hail(unsigned int p1, unsigned int p2, unsigned int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);

	Server.Hail(p1, p2, p3);
}

void __stdcall InterfaceItemUsed(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.InterfaceItemUsed(p1, p2);
}

void __stdcall JettisonCargo(unsigned int iClientID, struct XJettisonCargo const &jc)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.JettisonCargo(iClientID, jc);
}

void __stdcall LocationEnter(unsigned int p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(iClientID);

	Server.LocationEnter(p1, iClientID);
}

void __stdcall LocationExit(unsigned int p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(iClientID);

	Server.LocationExit(p1, iClientID);
}

void __stdcall LocationInfoRequest(unsigned int p1,unsigned int p2, bool p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);

	Server.LocationInfoRequest(p1, p2, p3);
}

void __stdcall MissionResponse(unsigned int p1, unsigned long p2, bool p3, unsigned int p4)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_UI(p4);

	Server.MissionResponse(p1, p2, p3, p4);
}

void __stdcall MissionSaveB(unsigned int iClientID, unsigned long p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_UI(p2);

	Server.MissionSaveB(iClientID, p2);
}

void __stdcall NewCharacterInfoReq(unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.NewCharacterInfoReq(iClientID); // doesn't do anything
}

void __stdcall PopUpDialog(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.PopUpDialog(p1, p2);
}

void __stdcall PushToServer(class CDAPacket *packet)
{
	ISERVER_LOG();

	Server.PushToServer(packet); // doesn't do anything
}

void __stdcall RTCDone(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.RTCDone(p1, p2);
}

void __stdcall ReqAddItem(unsigned int p1, char const *p2, int p3, float p4, bool p5, unsigned int p6)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_F(p4);
	ISERVER_LOGARG_UI(p5);
	ISERVER_LOGARG_UI(p6);

	Server.ReqAddItem(p1, p2, p3, p4, p5, p6);
}

void __stdcall ReqCargo(class EquipDescList const &edl, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqCargo(edl, iClientID); // doesn't do anything
}

void __stdcall ReqChangeCash(int p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqChangeCash(p1, iClientID);
}

void __stdcall ReqCollisionGroups(class std::list<struct CollisionGroupDesc,class std::allocator<struct CollisionGroupDesc> > const &p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqCollisionGroups(p1, iClientID);
}

void __stdcall ReqDifficultyScale(float p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_F(p1);
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqDifficultyScale(p1, iClientID);
}

void __stdcall ReqEquipment(class EquipDescList const &edl, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqEquipment(edl, iClientID);
}

void __stdcall ReqHullStatus(float p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_F(p1);
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqHullStatus(p1, iClientID);
}

void __stdcall ReqModifyItem(unsigned short p1, char const *p2, int p3, float p4, bool p5, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);
	ISERVER_LOGARG_F(p4);
	ISERVER_LOGARG_UI(p5);
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqModifyItem(p1, p2, p3, p4, p5, iClientID);
}

void __stdcall ReqRemoveItem(unsigned short p1, int p2, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_I(p2);
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqRemoveItem(p1, p2, iClientID);
}

void __stdcall ReqSetCash(int p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_I(p1);
	ISERVER_LOGARG_UI(iClientID);

	Server.ReqSetCash(p1, iClientID);
}

void __stdcall ReqShipArch(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.ReqShipArch(p1, p2);
}

void __stdcall RequestBestPath(unsigned int p1, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.RequestBestPath(p1, p2, p3);
}

void __stdcall RequestCancel(int p1, unsigned int p2, unsigned int p3, unsigned long p4, unsigned int p5)
{
	ISERVER_LOG();
	ISERVER_LOGARG_I(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_UI(p4);
	ISERVER_LOGARG_UI(p5);

	Server.RequestCancel(p1, p2, p3, p4, p5);
}

void __stdcall RequestCreateShip(unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.RequestCreateShip(iClientID);
}

void __stdcall RequestEvent(int p1, unsigned int p2, unsigned int p3, unsigned int p4, unsigned long p5, unsigned int p6)
{
	ISERVER_LOG();
	ISERVER_LOGARG_I(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_UI(p4);
	ISERVER_LOGARG_UI(p5);
	ISERVER_LOGARG_UI(p6);

	Server.RequestEvent(p1, p2, p3, p4, p5, p6);
}

void __stdcall RequestGroupPositions(unsigned int p1, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.RequestGroupPositions(p1, p2, p3);
}

void __stdcall RequestPlayerStats(unsigned int p1, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.RequestPlayerStats(p1, p2, p3);
}

void __stdcall RequestRankLevel(unsigned int p1, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.RequestRankLevel(p1, p2, p3);
}

void __stdcall RequestTrade(unsigned int p1, unsigned int p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);

	Server.RequestTrade(p1, p2);
}

void __stdcall SPBadLandsObjCollision(struct SSPBadLandsObjCollisionInfo const &p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.SPBadLandsObjCollision(p1, iClientID);
}

void __stdcall SPRequestInvincibility(unsigned int p1, bool p2, enum InvincibilityReason p3, unsigned int p4)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);
	ISERVER_LOGARG_UI(p4);

	Server.SPRequestInvincibility(p1, p2, p3, p4);
}

void __stdcall SPRequestUseItem(struct SSPUseItem const &p1, unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.SPRequestUseItem(p1, iClientID);
}

void __stdcall SPScanCargo(unsigned int const &p1, unsigned int const &p2, unsigned int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
	ISERVER_LOGARG_UI(p2);
	ISERVER_LOGARG_UI(p3);

	Server.SPScanCargo(p1, p2, p3);
}

void __stdcall SaveGame(struct CHARACTER_ID const &cId, unsigned short const *p2, unsigned int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_S(&cId);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_UI(p3);

	Server.SaveGame(cId, p2, p3);
}

void __stdcall SetActiveConnection(enum EFLConnection p1)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);

	Server.SetActiveConnection(p1); // doesn't do anything
}

void __stdcall SetInterfaceState(unsigned int p1, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(p1);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.SetInterfaceState(p1, p2, p3);
}

void __stdcall SetManeuver(unsigned int iClientID, struct XSetManeuver const &p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.SetManeuver(iClientID, p2);
}

void __stdcall SetMissionLog(unsigned int iClientID, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.SetMissionLog(iClientID, p2, p3);
}

void __stdcall SetTarget(unsigned int iClientID, struct XSetTarget const &p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.SetTarget(iClientID, p2);
}

void __stdcall SetTradeMoney(unsigned int iClientID, unsigned long p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
	ISERVER_LOGARG_UI(p2);

	Server.SetTradeMoney(iClientID, p2);
}

void __stdcall SetVisitedState(unsigned int iClientID, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.SetVisitedState(iClientID, p2, p3);
}

void __stdcall SetWeaponGroup(unsigned int iClientID, unsigned char *p2, int p3)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);
//	ISERVER_LOGARG_S(p2);
	ISERVER_LOGARG_I(p3);

	Server.SetWeaponGroup(iClientID, p2, p3);
}

void __stdcall Shutdown(void)
{
	ISERVER_LOG();

	Server.Shutdown();
}

bool __stdcall Startup(struct SStartupInfo const &p1)
{
	ISERVER_LOG();

	return Server.Startup(p1);
}

void __stdcall StopTradeRequest(unsigned int iClientID)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.StopTradeRequest(iClientID);
}

void __stdcall TractorObjects(unsigned int iClientID, struct XTractorObjects const &p2)
{
	ISERVER_LOG();
	ISERVER_LOGARG_UI(iClientID);

	Server.TractorObjects(iClientID, p2);
}

void __stdcall TradeResponse(unsigned char const *p1, int p2, unsigned int iClientID)
{
	ISERVER_LOG();
///	ISERVER_LOGARG_S(p1);
	ISERVER_LOGARG_I(p2);
	ISERVER_LOGARG_UI(iClientID);

	Server.TradeResponse(p1, p2, iClientID);
}

/**************************************************************************************************************
IServImpl hook entries
**************************************************************************************************************/

HOOKENTRY hookEntries[] =
{
	{(FARPROC)SubmitChat,				-0x08, 0},
	{(FARPROC)FireWeapon,				0x000, 0},
	{(FARPROC)ActivateEquip,			0x004, 0},
	{(FARPROC)ActivateCruise,			0x008, 0},
	{(FARPROC)ActivateThrusters,		0x00C, 0},
	{(FARPROC)SetTarget,				0x010, 0},
	{(FARPROC)TractorObjects,			0x014, 0},
	{(FARPROC)GoTradelane,				0x018, 0},
	{(FARPROC)StopTradelane,			0x01C, 0},
	{(FARPROC)JettisonCargo,			0x020, 0},
	{(FARPROC)Startup,					0x024, 0},
	{(FARPROC)Shutdown,					0x028, 0},
//	{(FARPROC)Update,					0x02C, 0}, // no need to add here, already hooked in DllMain
	{(FARPROC)ElapseTime,				0x030, 0},
	{(FARPROC)PushToServer,				0x034, 0}, // or SetActiveConnection?!
//	{(FARPROC)SwapConnections,			0x038, 0}, // ???
	{(FARPROC)Connect,					0x03C, 0},
	{(FARPROC)DisConnect,				0x040, 0},
	{(FARPROC)OnConnect,				0x044, 0},
	{(FARPROC)Login,					0x048, 0},
	{(FARPROC)CharacterInfoReq,			0x04C, 0},
	{(FARPROC)CharacterSelect,			0x050, 0},
	{(FARPROC)SetActiveConnection,		0x054, 0}, // or PushToServer?
	{(FARPROC)CreateNewCharacter,		0x058, 0},
	{(FARPROC)DestroyCharacter,			0x05C, 0},
	{(FARPROC)CharacterSkipAutosave,	0x060, 0},
	{(FARPROC)ReqShipArch,				0x064, 0},
	{(FARPROC)ReqHullStatus,			0x068, 0},
	{(FARPROC)ReqCollisionGroups,		0x06C, 0},
	{(FARPROC)ReqEquipment,				0x070, 0},
	{(FARPROC)ReqCargo,					0x074, 0},
	{(FARPROC)ReqAddItem,				0x078, 0},
	{(FARPROC)ReqRemoveItem,			0x07C, 0},
	{(FARPROC)ReqModifyItem,			0x080, 0},
	{(FARPROC)ReqSetCash,				0x084, 0},
	{(FARPROC)ReqChangeCash,			0x088, 0},
	{(FARPROC)BaseEnter,				0x08C, 0},
	{(FARPROC)BaseExit,					0x090, 0},
	{(FARPROC)LocationEnter,			0x094, 0},
	{(FARPROC)LocationExit,				0x098, 0},
	{(FARPROC)BaseInfoRequest,			0x09C, 0},
	{(FARPROC)LocationInfoRequest,		0x0A0, 0},
	{(FARPROC)GFObjSelect,				0x0A4, 0},
	{(FARPROC)GFGoodVaporized,			0x0A8, 0},
	{(FARPROC)MissionResponse,			0x0AC, 0},
	{(FARPROC)TradeResponse,			0x0B0, 0},
	{(FARPROC)GFGoodBuy,				0x0B4, 0},
	{(FARPROC)GFGoodSell,				0x0B8, 0},
	{(FARPROC)SystemSwitchOutComplete,	0x0BC, 0},
	{(FARPROC)PlayerLaunch,				0x0C0, 0},
	{(FARPROC)LaunchComplete,			0x0C4, 0},
	{(FARPROC)JumpInComplete,			0x0C8, 0},
	{(FARPROC)Hail,						0x0CC, 0},
	{(FARPROC)SPObjUpdate,				0x0D0, 0},
	{(FARPROC)SPMunitionCollision,		0x0D4, 0},
	{(FARPROC)SPBadLandsObjCollision,	0x0D8, 0},
	{(FARPROC)SPObjCollision,			0x0DC, 0},
	{(FARPROC)SPRequestUseItem,			0x0E0, 0},
	{(FARPROC)SPRequestInvincibility,	0x0E4, 0},
	{(FARPROC)SaveGame,					0x0E8, 0},
	{(FARPROC)MissionSaveB,				0x0EC, 0},
	{(FARPROC)RequestEvent,				0x0F0, 0},
	{(FARPROC)RequestCancel,			0x0F4, 0},
	{(FARPROC)MineAsteroid,				0x0F8, 0},
	{(FARPROC)CommComplete,				0x0FC, 0},
	{(FARPROC)RequestCreateShip,		0x100, 0},
	{(FARPROC)SPScanCargo,				0x104, 0},
	{(FARPROC)SetManeuver,				0x108, 0},
	{(FARPROC)InterfaceItemUsed,		0x10C, 0},
	{(FARPROC)AbortMission,				0x110, 0},
	{(FARPROC)RTCDone,					0x114, 0},
	{(FARPROC)SetWeaponGroup,			0x118, 0},
	{(FARPROC)SetVisitedState,			0x11C, 0},
	{(FARPROC)RequestBestPath,			0x120, 0},
	{(FARPROC)RequestPlayerStats,		0x124, 0},
	{(FARPROC)PopUpDialog,				0x128, 0},
	{(FARPROC)RequestGroupPositions,	0x12C, 0},
	{(FARPROC)SetMissionLog,			0x130, 0},
	{(FARPROC)SetInterfaceState,		0x134, 0},
	{(FARPROC)RequestRankLevel,			0x138, 0},
	{(FARPROC)InitiateTrade,			0x13C, 0},
	{(FARPROC)TerminateTrade,			0x140, 0},
	{(FARPROC)AcceptTrade,				0x144, 0},
	{(FARPROC)SetTradeMoney,			0x148, 0},
	{(FARPROC)AddTradeEquip,			0x14C, 0},
	{(FARPROC)DelTradeEquip,			0x150, 0},
	{(FARPROC)RequestTrade,				0x154, 0},
	{(FARPROC)StopTradeRequest,			0x158, 0},
	{(FARPROC)ReqDifficultyScale,		0x15C, 0},
	{(FARPROC)GetServerID,				0x160, 0},
	{(FARPROC)GetServerSig,				0x164, 0},
	{(FARPROC)DumpPacketStats,			0x168, 0},
	{(FARPROC)Dock,						0x16C, 0},
};

}
